/* Copyright 2010 Big Blue Brains
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.bigbluebrains.android;

import java.util.HashMap;
import java.util.Map;

public class ArabicHandler {
	private static Map<String, ArabicGlyph> glyphs = new HashMap<String, ArabicGlyph>(){
		{
			addGlyph("\u0621", null, null, null); 	  //hamza 3al satr
			addGlyph("\u0622", "\uFE82", null, null); //alef madda
			addGlyph("\u0623", "\uFE84", null, null); //alef hamza
			addGlyph("\u0624", "\uFE86", null, null); //waw hamza
			addGlyph("\u0625", "\uFE88", null, null); //alef ta7taha hamza
			addGlyph("\u0626", "\uFE8A", "\uFE8B", "\uFE8C"); //hamza 3ala nabra
			addGlyph("\u0627", "\uFE8E", null, null); //alef
			addGlyph("\u0628", "\uFE90", "\uFE91", "\uFE92"); //beh
			addGlyph("\u0629", "\uFE94", null, null); //teh marbota
			addGlyph("\u062A", "\uFE96", "\uFE97", "\uFE98"); //teh
			addGlyph("\u062B", "\uFE9A", "\uFE9B", "\uFE9C"); //theh
			addGlyph("\u062C", "\uFE9E", "\uFE9F", "\uFEA0"); //geem
			addGlyph("\u062D", "\uFEA2", "\uFEA3", "\uFEA4"); //7ah
			addGlyph("\u062E", "\uFEA6", "\uFEA7", "\uFEA8"); //7'ah
			addGlyph("\u062F", "\uFEAA", null, null); //dal
			addGlyph("\u0630", "\uFEAC", null, null); //zal
			addGlyph("\u0631", "\uFEAE", null, null); //reh
			addGlyph("\u0632", "\uFEB0", null, null); //zen
			addGlyph("\u0633", "\uFEB2", "\uFEB3", "\uFEB4"); //seen
			addGlyph("\u0634", "\uFEB6", "\uFEB7", "\uFEB8"); //sheen
			addGlyph("\u0635", "\uFEBA", "\uFEBB", "\uFEBC"); //sad
			addGlyph("\u0636", "\uFEBE", "\uFEBF", "\uFEC0"); //dad
			addGlyph("\u0637", "\uFEC2", "\uFEC3", "\uFEC4"); //tah
			addGlyph("\u0638", "\uFEC6", "\uFEC7", "\uFEC8"); //zah
			addGlyph("\u0639", "\uFECA", "\uFECB", "\uFECC"); //3en
			addGlyph("\u063A", "\uFECE", "\uFECF", "\uFED0"); //3'en
			addGlyph("\u0641", "\uFED2", "\uFED3", "\uFED4"); //feh
			addGlyph("\u0642", "\uFED6", "\uFED7", "\uFED8"); //qaf
			addGlyph("\u0643", "\uFEDA", "\uFEDB", "\uFEDC"); //kaf
			addGlyph("\u0644", "\uFEDE", "\uFEDF", "\uFEE0"); //lam
			addGlyph("\u0645", "\uFEE2", "\uFEE3", "\uFEE4"); //meem
			addGlyph("\u0646", "\uFEE6", "\uFEE7", "\uFEE8"); //noon
			addGlyph("\u0647", "\uFEEA", "\uFEEB", "\uFEEC"); //heh
			addGlyph("\u0648", "\uFEEE", null, null); //waw
			addGlyph("\u0649", "\uFEF0", null, null); //alef layena
			addGlyph("\u064A", "\uFEF2", "\uFEF3", "\uFEF4"); //yeh
			
			//ligatures [head = \u0644]
			addGlyph("\u0644\u0622", "\uFEF5", "\uFEF6", null, null); //lam alef madda
			addGlyph("\u0644\u0623", "\uFEF7", "\uFEF8", null, null); //lam alef hamza
			addGlyph("\u0644\u0624", "\uFEF9", "\uFEFA", null, null); //lam alef ta7taha hamza
			addGlyph("\u0644\u0627", "\uFEFB", "\uFEFC", null, null); //lam alef
			
			//symbols
			addGlyph(",", "\u060C", null, null, null);
			addGlyph(";", "\u061B", null, null, null);
			addGlyph("?", "\u061F", null, null, null);
			addGlyph("?", "\u061F", null, null, null);
			addGlyph("-", "\u0640", null, null, null);
			addGlyph("%", "\u066A", null, null, null);
			//add RLM after each of these characters for now
//			addGlyph("(", "(\u200F", null, null, null);
			addGlyph(")", ")\u200F", null, null, null);
			addGlyph("!", "!\u200F", null, null, null);
			addGlyph(".", ".\u200F", null, null, null);
			
			//numbers 0660 - 0669
			addGlyph("0", "\u0660", null, null, null);
			addGlyph("1", "\u0661", null, null, null);
			addGlyph("2", "\u0662", null, null, null);
			addGlyph("3", "\u0663", null, null, null);
			addGlyph("4", "\u0664", null, null, null);
			addGlyph("5", "\u0665", null, null, null);
			addGlyph("6", "\u0666", null, null, null);
			addGlyph("7", "\u0667", null, null, null);
			addGlyph("8", "\u0668", null, null, null);
			addGlyph("9", "\u0669", null, null, null);
		}
		
		private void addGlyph(String characters, String finalForm, String initialForm, String medialForm) {
			put(characters, new ArabicGlyph(characters, characters, initialForm, finalForm, medialForm));
		}
		
		private void addGlyph(String characters, String isolated, String finalForm, String initialForm, String medialForm) {
			put(characters, new ArabicGlyph(characters, isolated, initialForm, finalForm, medialForm));
		}
	};
	
	public static String shabbek(String mfarrat) {
		StringBuilder mshabbek = new StringBuilder(mfarrat.length());
		for(int i = 0, len = mfarrat.length() ; i < len ; i++) {
			String current = String.valueOf(mfarrat.charAt(i));
			boolean handlingLigature = false;
			ArabicGlyph currentGlyph = null;
			
			//all ligatures supported so far starts with lam and has a length of 2 characters
			if(current.equals("\u0644") && i+1 < len) {
				String possibleLigature = mfarrat.substring(i, i+2);
				currentGlyph = glyphs.get(possibleLigature);
				if(currentGlyph != null) {
					current = possibleLigature;
					handlingLigature = true;
				}
			} 
			
			if(!handlingLigature) {
				currentGlyph = glyphs.get(current);
			}
			
			//latin or unmapped
			if(currentGlyph == null) {
				mshabbek.append(current);
				continue;
			}
			
			boolean previousCanConnectToNext = (i > 0 && glyphs.containsKey(String.valueOf(mfarrat.charAt(i-1))))?glyphs.get(String.valueOf(mfarrat.charAt(i-1))).canConnectToNext():false;
			boolean nextCanConnectToPrevious = (i < len - 1 && glyphs.containsKey(String.valueOf(mfarrat.charAt(i+1))))?glyphs.get(String.valueOf(mfarrat.charAt(i+1))).canConnectToPrevious():false;
			
			if(previousCanConnectToNext && nextCanConnectToPrevious && currentGlyph.canConnectToBoth()) {
				mshabbek.append(currentGlyph.getMedialForm());
			} else if(previousCanConnectToNext && currentGlyph.canConnectToPrevious()) {
				mshabbek.append(currentGlyph.getFinalForm());
			} else if(nextCanConnectToPrevious && currentGlyph.canConnectToNext()) {
				mshabbek.append(currentGlyph.getInitialForm());
			} else {
				mshabbek.append(currentGlyph.getIsolatedForm());
			}
			
			
			if(handlingLigature) {
				i+=currentGlyph.getCharacters().length()-1;
			}
		}
		return mshabbek.toString();
	}
}
